import { AnimationComponent, UIOpacity, UITransform, tween } from 'cc';
// Learn TypeScript:
//  - https://docs.cocos.com/creator/2.4/manual/en/scripting/typescript.html
// Learn Attribute:
//  - https://docs.cocos.com/creator/2.4/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
//  - https://docs.cocos.com/creator/2.4/manual/en/scripting/life-cycle-callbacks.html

import { Color, Node, Sprite, SpriteFrame, Tween, Vec2, easing, sp, v2, v3 } from "cc";
import { randomOf } from '../Utils/Utils';
import { PM } from "./PoolManager";
import Res from './Res';

export default class EM {
    private static instance: EM = null;
    public static get Ins(): EM {
        if (this.instance == null)
            this.instance = new EM();
        return this.instance;
    }
    private static shakeNodeMap: Map<Node, Tween<Node>> = new Map();
    private static nodePos: Map<Node, Vec2> = new Map();
    /**晃动节点 */
    static shakeNode(node: Node, param?: { times?: number, duration?: number, amp?: number, srcPos?: Vec2 }) {

        if (this.shakeNodeMap.has(node)) {
            this.shakeNodeMap.get(node).stop();
            let pos = this.nodePos.get(node);
            node.setPosition(v3(pos.x, pos.y));
            this.shakeNodeMap.delete(node);
        }
        if (!param) {
            param = { times: 6, duration: 0.2, amp: 10 };
        }
        let times = param.times || 6;
        let duration = param.duration || 0.2;
        let amp = param.amp || 10;
        let nodePos = node.getPosition();
        let srcPos = param.srcPos || v2(nodePos.x, nodePos.y);
        this.nodePos.set(node, srcPos);
        let destPos = new Vec2();
        let nodeTween: Tween<Node> = tween(node);
        for (let i = 0; i < times; ++i) {
            if (i == times - 1) {
                destPos.x = destPos.y = 0;
            } else {
                Vec2.random(destPos, amp);
            }
            let endPos = srcPos.add(destPos);
            nodeTween.to(duration / times, { position: v3(endPos.x, endPos.y) });
        }
        let action = nodeTween.start();
        this.shakeNodeMap.set(node, action);
    }
    static emit(sprite: SpriteFrame, center: Vec2, numVar: Vec2, scaleVar: Vec2, spinVar: Vec2, timeVar: Vec2, distanceVar: Vec2, colorVar: Color[] = [Color.WHITE], parent: Node) {
        let effectNode = new Node();
        effectNode.setParent(parent);
        effectNode.position = v3(center.x, center.y);
        let num = randomOf(numVar.x, numVar.y);
        for (let i = 0; i < num; i++) {
            let node = new Node();
            node.setParent(effectNode);
            node.getComponent(UITransform).width = 50;
            node.getComponent(UITransform).height = 50;
            let spriteCom = node.addComponent(Sprite);
            spriteCom.getComponent(UIOpacity).opacity = 255;
            spriteCom.spriteFrame = sprite;
            let scale = randomOf(scaleVar.x, scaleVar.y);
            let spin = randomOf(spinVar.x, spinVar.y);
            let time = randomOf(timeVar.x, timeVar.y);
            let distance = randomOf(distanceVar.x, distanceVar.y, t => t * (2 - t));

            node.position = v3();
            node.scale = v3();
            node.angle = 0;
            let emitAngle = randomOf(0, 360);
            let endPos = v3(Math.cos(emitAngle * Math.PI / 180) * distance, Math.sin(emitAngle * Math.PI / 180) * distance);
            tween(node).to(time, { scale: v3(scale, scale, 1), angle: spin, position: endPos }, { easing: t => -Math.pow(t - 1, 4) + 1 }).call(() => {
                tween(node.getComponent(UIOpacity)).to(0.5, { opacity: 0 }).call(() => {
                    effectNode.destroy();
                }).start();
            }).start();
        }
    }
    /**释放指定url的预制体，使其突然出现后慢慢消失 */
    static sparklePrefabs(url: string, parent: Node, pos: Vec2, time: number = 1) {
        return new Promise<void>(async (resolve) => {
            let node = PM.Get(Res.Ins.getPrefab(url));
            node.setParent(parent);
            node.position = v3(pos.x, pos.y);
            node.getComponent(UIOpacity).opacity = 255;
            tween(node.getComponent(UIOpacity)).to(time, { opacity: 0 }).call(() => { PM.Put(node); resolve() }).start();

        })
    }
    /**释放指定url的预制体，播放url同名动画，播放完毕之后自动销毁 */
    static async animPrefab(url: string, parent: Node, pos: Vec2, init: (node: Node) => void) {
        return new Promise<void>(async (resolve) => {
            let node = PM.Get(Res.Ins.getPrefab(url));
            node.setParent(parent);
            node.position = v3(pos.x, pos.y);
            init && init(node);
            let anim = node.getComponent(AnimationComponent);
            anim.play(url);
            anim.once(AnimationComponent.EventType.FINISHED, () => {
                PM.Put(node);
                resolve();
            });
        });
    }
    static angleShake(node: Node, param?: { times?: number, duration?: number, amp?: number }, call?: Function) {
        if (!param) {
            param = { times: 3, duration: 0.35, amp: 7 };
        }
        let times = param.times || 3;
        let duration = param.duration || 0.35;
        let amp = param.amp || 7;
        let timeStep = duration / (times + 1);
        let nodeTween = tween(node).to(timeStep / 2, { angle: amp }, { easing: easing.sineInOut });
        for (let i = 0; i < times; i++) {
            nodeTween = nodeTween.to(timeStep / 2, { angle: -amp }, { easing: easing.sineInOut })
                .to(timeStep / 2, { angle: amp }, { easing: easing.sineInOut });
        }
        nodeTween = nodeTween.to(timeStep / 2, { angle: 0 }, { easing: easing.sineInOut });
        nodeTween.call(() => call && call()).start();
    }
    static async animSpinePrefab(url: string, parent: Node, pos: Vec2, init: (node: Node) => void) {
        return new Promise<void>(async (resolve) => {
            let node = PM.Get(Res.Ins.getPrefab(url));
            node.setParent(parent);
            node.position = v3(pos.x, pos.y);
            init && init(node);
            let anim = node.getComponent(sp.Skeleton);
            anim.setAnimation(0, url, false);
            // anim.setEndListener(() => {
            //     anim.setEndListener(null);
            //     PM.Put(node);
            //     resolve();

            // })

        });
    }
    private static prefabNodeMap: Map<number, Node> = new Map();
    private static cnt = 0;
    /**释放指定url的预制体，播放url同名动画，返回id */
    static startAnimEffect(url: string, parent: Node, pos: Vec2, init: (node: Node) => void = e => { }) {
        let node = PM.Get(Res.Ins.getPrefab(url));
        node.setParent(parent);
        node.position = v3(pos.x, pos.y);
        init && init(node);
        let anim = node.getComponent(AnimationComponent);
        anim.play(url);
        let id = this.cnt++;
        this.prefabNodeMap.set(id, node);
        return id;
    }
    /**销毁指定id的预制体动画 */
    static stopAnimEffect(id: number) {
        let node = this.prefabNodeMap.get(id);
        if (node) {
            PM.Put(node);
            this.prefabNodeMap.delete(id);
        }
    }
    static async animPrefab2(url: string, parent: Node, pos: Vec2, call: Function) {
        let node = PM.Get(Res.Ins.getPrefab(url));
        node.setParent(parent);
        node.position = v3(pos.x, pos.y);
        let anim = node.getComponent(AnimationComponent);
        anim.play(url);
        anim.once(AnimationComponent.EventType.FINISHED, () => {
            PM.Put(node);
            call && call();
        });
        return node;

    }
}
